#pragma once

#include <cppunit/config/SourcePrefix.h>
#include <iostream>
#include <string>
#include <algorithm>
#include "TestCommonParent.h"

void CommonParentTest::setUp(){
	validLineInputWhile.push_back(2);
	validLineInputWhile.push_back(5);
	validLineInputWhile.push_back(6);
	validLineInputWhile.push_back(7);
	validLineInputWhile.push_back(8);
	validLineInputWhile.push_back(9);
	validLineInputWhile.push_back(10);
	validLineInputWhile.push_back(15);
	validLineInputWhile.push_back(20);
	validLineInputWhile.push_back(25);

	validParentInputWhile.push_back(2);
	validParentInputWhile.push_back(2);
	validParentInputWhile.push_back(6);
	validParentInputWhile.push_back(6);
	validParentInputWhile.push_back(6);
	validParentInputWhile.push_back(9);
	validParentInputWhile.push_back(9);
	validParentInputWhile.push_back(9);
	validParentInputWhile.push_back(20);
	validParentInputWhile.push_back(20);

	//TODO
	//validLineInputIf;
	//validParentInputIf; 

	for(unsigned int n=0; n<validParentInputWhile.size(); n++){
		invalidLineInput.push_back(-1);
		nonExistLineInput.push_back(50);
	}

	commonParent = CommonParent();
}

void CommonParentTest::tearDown(){
	validLineInputWhile.clear();
	validParentInputWhile.clear(); 
	validLineInputIf.clear();
	validParentInputIf.clear(); 
	invalidLineInput.clear();
	nonExistLineInput.clear();
}

// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( CommonParentTest );

void CommonParentTest::testSetCommonWhile(Type::List::Line lines, Type::List::Line parents, 
	bool pass, std::string failMsg){
		Type::Index::Line rowLine, colLine, earliest;
		bool tmpTF;
		unsigned int j, k;

		CPPUNIT_ASSERT_MESSAGE(msg + "(line and parents different)", lines.size() == parents.size());

		// construct line matrix
		Type::Map::ParentMatrix matrix;
		for(j=0; j<lines.size(); j++){
			colLine = lines.at(j);
			Type::Map::ParentMap row;

			for(k=0; k<lines.size(); k++){
				rowLine = lines.at(k);

				if(k == 0){
					earliest = parents.front();
				}else if (k != j){
					earliest = parents.at(Utilities::getIndexBoundedBySize(k-1, parents.size()));
				}else{
					earliest = parents.at(Utilities::getIndexBoundedBySize(k, parents.size()));
				}

				row.insert(std::make_pair<Type::Index::Line, Type::Index::Line>(rowLine, earliest));
			}
			matrix.insert(std::make_pair<Type::Index::Line, Type::Map::ParentMap>(colLine, row));
		}

		tmpTF = commonParent.setCommon(Type::Entity::WHILE_LINE_ENTITY,matrix);
		if(!pass){
			tmpTF = !tmpTF;
		}

		CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + "(setting line matrix)", tmpTF);
}

void CommonParentTest::testGetCommonWhile(Type::List::Line lines, Type::List::Line parents, 
	bool pass, std::string failMsg){
		Type::Index::Line rowLine, colLine, earliest;
		bool tmpTF;
		unsigned int j, k;
		CPPUNIT_ASSERT_MESSAGE(msg + "(line and parents different)", lines.size() == parents.size());

		for(j=0; j<lines.size(); j++){
			colLine = lines.at(j);

			for(k=0; k<lines.size(); k++){
				rowLine = lines.at(k);

				if(k == 0){
					earliest = parents.front();
				}else if (k != j){
					earliest = parents.at(Utilities::getIndexBoundedBySize(k-1, parents.size()));
				}else{
					earliest = parents.at(Utilities::getIndexBoundedBySize(k, parents.size()));
				}

				tmpTF = commonParent.getCommon(Type::Entity::WHILE_LINE_ENTITY, colLine, rowLine) == earliest;
				if(!pass){
					tmpTF = !tmpTF;
				}

				CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + "(getting line matrix)", tmpTF);
			}
		}
}

void CommonParentTest::testIsCommonWhile(Type::List::Line lines, Type::List::Line parents, 
	bool pass, std::string failMsg){
		Type::Index::Line rowLine, colLine, earliest;
		bool tmpTF;
		unsigned int j, k;
		CPPUNIT_ASSERT_MESSAGE(msg + "(line and parents different)", lines.size() == parents.size());

		for(j=0; j<lines.size(); j++){
			colLine = lines.at(j);

			for(k=0; k<lines.size(); k++){
				rowLine = lines.at(k);

				if(k == 0){
					earliest = parents.front();
				}else if (k != j){
					earliest = parents.at(Utilities::getIndexBoundedBySize(k-1, parents.size()));
				}else{
					earliest = parents.at(Utilities::getIndexBoundedBySize(k, parents.size()));
				}

				tmpTF = commonParent.isCommon(Type::Entity::WHILE_LINE_ENTITY, colLine, rowLine, earliest);
				if(!pass){
					tmpTF = !tmpTF;
				}

				CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + "(is common while)", tmpTF);
			}
		}
}

void CommonParentTest::testSetCommonIf(Type::List::Line lines, Type::List::Line parents, 
	bool pass, std::string failMsg){
		//TODO
}

void CommonParentTest::testGetCommonIf(Type::List::Line lines, Type::List::Line parents, 
	bool pass, std::string failMsg){
		//TODO
}

void CommonParentTest::testIsCommonIf(Type::List::Line lines, Type::List::Line parents, 
	bool pass, std::string failMsg){
		//TODO
}

// method to test the setting of line matrix for common parents
void CommonParentTest::testSetCommon(){
	std::cout<<std::endl<<"CommonParent setCommon()"<<std::endl;

	// verify setting valid line, parent for common while will always return true;
	msg = "Failed at setting valid line, parent for common while";
	testSetCommonWhile(validLineInputWhile, validParentInputWhile, true, msg);

	// verify setting valid line, invalid parent for common while will always return true;
	msg = "Failed at setting valid line, invalid parent for common while";
	testSetCommonWhile(validLineInputWhile, invalidLineInput, false, msg);

	// verify setting invalid line, valid parent for common while will always return true;
	msg = "Failed at setting invalid line, valid parent for common while";
	testSetCommonWhile(invalidLineInput, validParentInputWhile, false, msg);

	// verify setting valid line, parent for common if will always return true;
	msg = "Failed at setting valid line, parent for common if";
	testSetCommonIf(validLineInputIf, validParentInputIf, true, msg);
}

// method to test the getting of records of common parents
void CommonParentTest::testGetCommon(){
	std::cout<<std::endl<<"CommonParent getCommon()"<<std::endl;

	testSetCommon();

	// verify common while parent retrieval of valid line will always correct;
	msg = "Failed at getting common while parent of valid line 1, 2";
	testGetCommonWhile(validLineInputWhile, validParentInputWhile, true, msg);

	// verify common while parent retrieval of invalid line will always false;
	msg = "Failed at getting common while parent of invalid line";
	testGetCommonWhile(invalidLineInput, validParentInputWhile, false, msg);

	// verify common if parent retrieval of valid line will always correct;
	msg = "Failed at getting common if parent of valid line";
	testGetCommonIf(validLineInputIf, validParentInputIf, true, msg);

	// verify common if parent retrieval of invalid line will always false;
	msg = "Failed at getting common if parent of invalid line";
	testGetCommonIf(invalidLineInput, validParentInputIf, false, msg);
}

// method to test the correctness of common parent records
void CommonParentTest::testIsCommon(){
	std::cout<<std::endl<<"CommonParent isCommon()"<<std::endl;

	testSetCommon();

	// verify correctness of valid line with valid common while parent
	msg = "Failed checking correctness of valid line with valid common while parent";
	testIsCommonWhile(validLineInputWhile, validParentInputWhile, true, msg);

	// verify correctness of invalid line with valid common while parent
	msg = "Failed checking correctness of invalid line with valid common while parent";
	testIsCommonWhile(invalidLineInput, validParentInputWhile, false, msg);

	// verify correctness of valid line with invalid common while parent
	msg = "Failed checking correctness of valid line with invalid common while parent";
	testIsCommonWhile(validLineInputWhile, invalidLineInput, false, msg);

	// verify correctness of valid line with valid common if parent
	msg = "Failed checking correctness of valid line with valid common if parent";
	testIsCommonIf(validLineInputIf, validParentInputIf, true, msg);

	// verify correctness of invalid line with valid common if parent
	msg = "Failed checking correctness of invalid line with valid common if parent";
	testIsCommonIf(invalidLineInput, validParentInputIf, false, msg);

	// verify correctness of valid line with invalid common if parent
	msg = "Failed checking correctness of valid line with invalid common if parent";
	testIsCommonIf(validLineInputIf, invalidLineInput, false, msg);
}